﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2023 Glodon.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Owner: zhuxf  
// Co-Owner: 

#include "ViewSpecificElement.h"

#include "IUiDocumentViewManager.h"
#include "IElementModelShape.h"
#include "IElementPosition.h"
#include "IGraphicsElementShape.h"
#include "IInstance.h"
#include "IDocument.h"
#include "DbObjectUtils.h"
#include "IUiDocument.h"
#include "UiCommonDialog.h"
#include "IUserTransaction.h"
#include "IGraphicsLine.h"
#include "IModelView.h"
#include "IElementParentReporter.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
#include "GcmpCommandState.h"
#include "IGenericElement.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "ILine3d.h"
#include "IArc2d.h"
#include "IPolyCurve.h"
#include "IPolygon.h"
#include "GmBodyBuilder.h"
#include "IBody.h"
#include "IGraphicsBRepBody.h"
#include "IElementTransformationComponent.h"


using namespace gcmp;
using namespace Sample;

namespace Sample
{
    class SampleViewSpecificElementTransformationComponent : public gcmp::NdbObjectSchematic, public gcmp::IElementTransformationComponent
    {
        DBOBJECT_DATA_BEGIN_AND_QUICK_CAST_FROM(Sample, SampleViewSpecificElementTransformationComponent, gcmp::NdbObjectSchematic, BFC67FDF - 7ED1 - 44AA - B715 - 76783DEB9316, GRepModule, gcmp::IElementTransformationComponent)
            DATA_TRANSIENT(gcmp::IElement*, pOwnerElement)
            DBOBJECT_DATA_END
    public:
        virtual bool Translate(const IElementMoveContext& moveContext) override
        {
            const Vector3d& translation = moveContext.GetMoveVector();
            if (translation.IsZero())
            {
                return true;
            }

            Matrix4d translateMatrix;
            translateMatrix.MakeTranslate(translation.X(), translation.Y(), translation.Z());
            return Transform(translateMatrix);
        }

        virtual bool Rotate(const Vector3d& pointOnVec, const Vector3d& rotateDir, double rotateAngle) override
        {
            const double num2PI = std::floor(rotateAngle / gcmp::Constants::Constants::MATH_2PI);
            const double angleIn2PI = rotateAngle - num2PI * gcmp::Constants::Constants::MATH_2PI;
            if (MathUtils::IsZero(angleIn2PI))
            {
                return true;
            }

            Matrix4d rotationMatrix;
            rotationMatrix.MakeRotate(pointOnVec, rotateDir, rotateAngle);
            return Transform(rotationMatrix);
        }

        virtual bool Transform(const Matrix4d& matrix) override
        {
            if (matrix.IsIdentity())
            {
                return true;
            }

            IElement* pElement = GetOwnerElement();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"pElement为空", L"liangcw", L"2022-08-18");
            IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElement);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空", L"liangcw", L"2022-08-18");
            SampleViewSpecificElement* pViewSpecificElement = quick_cast<SampleViewSpecificElement>(pGenericElement->GetExternalObject());
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pViewSpecificElement, L"pViewSpecificElement为空", L"liangcw", L"2022-08-18");
            pViewSpecificElement->Transform(matrix);

            IElementPosition* pPositionBehavior = pElement->GetElementPosition();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pPositionBehavior, L"pPositionBehavior为空", L"wangzy-g", L"2019-06-06");

            return pPositionBehavior->Transform(matrix);
        }

        virtual NdbObject* GetTopOwnerObject() const override
        {
            return quick_cast<gcmp::NdbObject>(m_pOwnerElement);
        }

        virtual bool CanBeMoved(std::wstring* explanation = nullptr) const override
        {
            return true;
        }

        virtual bool CanBeRotated(std::wstring* explanation = nullptr) const override
        {
            return true;
        }

        virtual bool CanBeScaled(std::wstring* explanation = nullptr) const override
        {
            return false;
        }

        virtual bool Scale(const Vector3d& basePt, float scaleFactor) override
        {
            return false;
        }

        virtual IElement* GetOwnerElement() override
        {
            return m_pOwnerElement;
        }

        virtual const IElement* GetOwnerElement() const override
        {
            return m_pOwnerElement;
        }

        virtual bool SetOwnerElement(IElement* pOwnerElement) override
        {
            m_pOwnerElement = pOwnerElement;
            return true;
        }
    };

    DBOBJECT_DATA_DEFINE(SampleViewSpecificElementTransformationComponent)
    {
    }
}

DBOBJECT_DATA_DEFINE(SampleViewSpecificElement)
{
    m_pOwnerElement = nullptr;
}

NdbObject* SampleViewSpecificElement::GetTopOwnerObject() const
{
    return quick_cast<gcmp::NdbObject>(m_pOwnerElement);
}

void SampleViewSpecificElement::ReportParents(IElementParentReporter& elementParentReporter) const
{
    const IElement* pElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"IElement为空", L"GDMP", L"2023-09-30");
    elementParentReporter.ReportStrong(pElement->GetElementId());
}

void SampleViewSpecificElement::UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds)
{
    return;
}

bool SampleViewSpecificElement::Transform(const Matrix4d& matrix)
{
    IElement* pElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"pElement为空", L"liangcw", L"2022-08-18");
    IElementModelShape* pModelShape = pElement->GetElementModelShape();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelShape, L"pModelShape为空", L"liangcw", L"2022-08-18");
    OwnerPtr<IGraphicsElementShape> pGraphicsElementShape = pModelShape->TransferGraphicsElementShape();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGraphicsElementShape, L"pGraphicsElementShape为空", L"liangcw", L"2022-08-18");
    pGraphicsElementShape->Transform(matrix);
    pModelShape->SetGraphicsElementShape(TransferOwnership(pGraphicsElementShape));
    return true;
}

SampleViewSpecificElement* SampleViewSpecificElement::Create(gcmp::IDocument* pDocument, gcmp::ElementCreationOptions eco /*= gcmp::ElementCreationOptions::Normal*/)
{
    OwnerPtr<SampleViewSpecificElement> opViewSpecificElem = NEW_AS_OWNER_PTR(SampleViewSpecificElement);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opViewSpecificElem, L"创建opViewSpecificElem失败", L"GDMP", L"2024-03-30");

    SampleViewSpecificElement* pViewSpecificElem = opViewSpecificElem.get();

    IGenericElement* pGenericElement = IGenericElement::Create(
        pDocument, TransferOwnership(opViewSpecificElem),
        SampleViewSpecificElement::GetClassId().GetGuid(),
        BuiltInCategoryUniIdentities::BICU_FORM,
        ElementCreationOptions::Normal);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElement, L"创建IGenericElement失败", L"GDMP", L"2024-03-30");

    Coordinate3d coord;
    IElementPosition::CreatePoint2dOnAssociatedCoordinatePositionBehavior(pGenericElement, coord, Vector3d::Zero, Vector3d::UnitX, Vector3d::UnitY);

    OwnerPtr<ViewSpecificShapeCustomComponent> opViewSpecificBehavior = NEW_AS_OWNER_PTR(ViewSpecificShapeCustomComponent);
    pGenericElement->SetViewSpecificShapeComponent(TransferOwnership(opViewSpecificBehavior));

    OwnerPtr<SampleViewSpecificElementTransformationComponent> opTransformComponent = NEW_AS_OWNER_PTR(SampleViewSpecificElementTransformationComponent);
    pGenericElement->SetElementTransformationComponent(TransferOwnership(opTransformComponent));

    // 创建球体
    OwnerPtr<IBody> opSphere = GmBodyBuilder::CreateSphereBody(Vector3d::Zero, Vector3d::UnitZ, 500);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opSphere, L"opSphere为空", L"GDMP", L"2024-03-30");
    OwnerPtr<IGraphicsBRepBody> opBRepShellBody = IGraphicsBRepBody::Create(TransferOwnership(opSphere));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opBRepShellBody, L"opBRepShellBody为空", L"GDMP", L"2024-03-30");
    gcmp::OwnerPtr<IGraphicsElementShape> opGRep = IGraphicsElementShape::Create(GraphicsRenderLayer::Model);
    opGRep->AddChild(TransferOwnership(opBRepShellBody));

    IElementModelShape* pModelShape = pGenericElement->GetElementModelShape();
    pModelShape->SetGraphicsElementShape(TransferOwnership(opGRep));

    return pViewSpecificElem;
}

DBOBJECT_DATA_DEFINE(ViewSpecificShapeCustomComponent) 
{
    m_GraphicsNodeVisibilityCustomizer = nullptr;
}

Sample::ViewSpecificShapeCustomComponent::~ViewSpecificShapeCustomComponent()
{
}

bool ViewSpecificShapeCustomComponent::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;
    IGraphicsNodeVisibilityCustomizer* pCustomizer = GetGraphicsNodeVisibilityCustomizerFW__().get();
    if (pCustomizer)
    {
        pCustomizer->SetOwnerElement(pOwnerElement);
    }
    return true;
}

gcmp::NdbObject * Sample::ViewSpecificShapeCustomComponent::GetTopOwnerObject() const
{
    return quick_cast<gcmp::NdbObject>(m_pOwnerElement);
}

bool ViewSpecificShapeCustomComponent::IsVisibleInModelView(const gcmp::IModelView* pModelView) const
{
    return true;
}

gcmp::OwnerPtr<IGraphicsElementShape> ViewSpecificShapeCustomComponent::CreateViewSpecificElementShape(const IModelView* pModelView) const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelView, L"pModelView为空", L"liuyx-e", L"2019-06-21");
    gcmp::OwnerPtr<IGraphicsElementShape> opGRep = nullptr;
    if (pModelView->GetViewType() == BuiltInViewType::TwoDimensional)
    {
        Vector3d viewUpDir = pModelView->GetUpDirection();

        opGRep = IGraphicsElementShape::Create(GraphicsRenderLayer::Model);
        OwnerPtr<IGraphicsLine> upLine = IGraphicsLine::Create(Vector3d(0, 0, 0), viewUpDir * 1000);
        opGRep->AddChild(TransferOwnership(upLine));
        
        // 这里必须用const接口，否则会触发事务
        const IElement* pConstOwnerElement = m_pOwnerElement;
        const IElementPosition* pPosition = pConstOwnerElement->GetElementPosition();
        Matrix4d mat = pPosition->ComputeLocalToWorldCoordinateSystemTransformMatrix();
        opGRep->Transform(mat);
    }
    else
    {
        return nullptr;
    }
    return TransferOwnership(opGRep);
}

void ViewSpecificShapeCustomComponent::SetRenderPriorityOffsetProvider(OwnerPtr<IRenderPriorityOffsetProvider> opProvider)
{
    SetRenderPriorityOffsetProvider__(TransferOwnership(opProvider));
}

const IRenderPriorityOffsetProvider* ViewSpecificShapeCustomComponent::GetRenderPriorityOffsetProvider() const
{
    return GetRenderPriorityOffsetProvider__().get();
}

IRenderPriorityOffsetProvider* ViewSpecificShapeCustomComponent::GetRenderPriorityOffsetProvider()
{
    return GetRenderPriorityOffsetProviderFW__().get();
}

void ViewSpecificShapeCustomComponent::SetGraphicsNodeVisibilityCustomizer(OwnerPtr<IGraphicsNodeVisibilityCustomizer> opCustomizer)
{
    if (opCustomizer)
    {
        opCustomizer->SetOwnerElement(GetOwnerElement());
    }
    SetGraphicsNodeVisibilityCustomizer__(TransferOwnership(opCustomizer));
}

const IGraphicsNodeVisibilityCustomizer* ViewSpecificShapeCustomComponent::GetGraphicsNodeVisibilityCustomizer() const
{
    return GetGraphicsNodeVisibilityCustomizer__().get();
}

IGraphicsNodeVisibilityCustomizer* ViewSpecificShapeCustomComponent::GetGraphicsNodeVisibilityCustomizer()
{
    return GetGraphicsNodeVisibilityCustomizerFW__().get();
}
